/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.java; import java.io.*; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import sun.tools.java.*; import sun.tools.java.Identifier; import sun.tools.java.Package; import sun.tools.javac.*; import org.openide.filesystems.FileObject; import org.openide.filesystems.Repository; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.src.SourceElement; import org.openide.util.io.NullOutputStream; /** Supplies our compiler environment. * @author Ales Novak * @version 0.21 June 19, 1998 */ public class CoronaEnvironment extends BatchEnvironment { /** may be null */ private ErrConsumer errConsumer; /** list of errors */ ErrorMessage errors; /** a variable indicating not to throw CompilerException if there were syntax errors for example */ boolean thereWereErrors; /** file with errors */ String errorFileName; /** vector of deprecated files * @associates Object*/ Vector deprecationFiles; /** our srcClassPath refernce */ ClassPath srcPath; /** our binClassPath reference */ ClassPath binPath; /** hashtable with all registered files (FileObject, CoronaClassFile) * @associates CoronaClassFile*/ private Hashtable list = new Hashtable (); /** err offsets */ private static int OFFSET_BITS = sun.tools.java.Constants.WHEREOFFSETBITS; private static long OFFSET_BITS_MASK = sun.tools.java.Constants.MAXFILESIZE; /** Creates new Environment. * @param srcClassPath - java files are searched here * @param binClassPath - class files are searched here * @param consumer error consumer */ public CoronaEnvironment(CoronaClassPath srcClassPath, CoronaClassPath binClassPath, ErrConsumer consumer) { super(new NullOutputStream (), srcClassPath, binClassPath); srcClassPath.attachToEnvironment (this); binClassPath.attachToEnvironment (this); errConsumer = consumer; deprecationFiles = new Vector(); srcPath = srcClassPath; binPath = binClassPath; } /** * @return a String with classpath */ private static String getPath() { char c = java.io.File.separatorChar; return System.getProperty("java.class.path"); // + c + ".." + c + "lib" + c + "tools.jar"; } /** Obtains a CoronaClassFile for a file object. Keeps the list of * all created objects. * * @param fo file object * @return the file */ public /* synchronized */ CoronaClassFile getClassFile (FileObject fo) { CoronaClassFile cf = (CoronaClassFile)list.get (fo); if (cf == null) { cf = new CoronaClassFile (fo); list.put (fo, cf); } return cf; } /** Test if the file has been proceeded. * @param fo file object to test * @return true if the has been proceeded. */ public boolean proceeded (FileObject fo) { return list.get (fo) != null; } /** sets the error consumer */ public void setConsumer (ErrConsumer err) { errConsumer = err; } /** inserts error to the list of errors at position i */ public boolean insertError(long i, String string) { if (errConsumer == null) { return false; } if (errors == null || errors.where > i) { ErrorMessage errorMessage1 = new ErrorMessage(i, string); errorMessage1.next = errors; errors = errorMessage1; } else { if (errors.where == i && errors.message.equals(string)) return false; ErrorMessage msg1, msg2; for (msg1 = errors; (msg2 = msg1.next) != null && msg2.where < i; msg1 = msg2); ErrorMessage msg3; while ((msg3 = msg1.next) != null && msg3.where == i) { if (msg3.message.equals(string)) return false; msg1 = msg3; } ErrorMessage msg4 = new ErrorMessage(i, string); msg4.next = msg1.next; msg1.next = msg4; } return true; } /** reports error */ public void reportError(Object object, long i, String string1, String string2) { if (object == null) { if (errorFileName != null) { flushErrors(); errorFileName = null; } if (string1.startsWith("warn.")) // NOI18N { if (warnings()) { nwarnings++; output(string2); } return; } output(new StringBuffer("error: ").append(string2).toString()); // NOI18N nerrors++; flags |= 65536; return; } else if (object instanceof String) { String string3 = (String)object; if (!string3.equals(errorFileName)) { flushErrors(); errorFileName = string3; } if (string1.startsWith("warn.")) // NOI18N { if (string1.indexOf("is.deprecated") >= 0) // NOI18N { ndeprecations++; if (!deprecationFiles.contains(object)) deprecationFiles.addElement(object); if (!deprecation()) return; } nwarnings++; if (!warnings()) return; } else { nerrors++; flags |= 65536; } insertError(i, string2); return; } if (object instanceof ClassFile) { reportError(((ClassFile)object).getPath(), i, string1, string2); return; } if (object instanceof Identifier) { reportError(object.toString(), i, string1, string2); return; } if (object instanceof ClassDeclaration) { try { reportError(((ClassDeclaration)object).getClassDefinition(this), i, string1, string2); } catch (ClassNotFound classNotFound) { reportError(((ClassDeclaration)object).getName(), i, string1, string2); return; } return; } if (object instanceof ClassDefinition) { ClassDefinition classDefinition = (ClassDefinition)object; if (!string1.startsWith("warn.")) // NOI18N classDefinition.setError(); reportError(classDefinition.getSource(), i, string1, string2); return; } if (object instanceof MemberDefinition) { ClassDeclaration cdecl; cdecl = ((MemberDefinition) object).getClassDeclaration(); reportError(cdecl, i, string1, string2); return; } output(":error=" + string1 + ":" + string2); // NOI18N } /** Method thanks to we have to create our own class */ public void flushErrors() { if (errors == null) { return; } if (errConsumer == null) { errors = null; return; } CoronaClassFile cfile = null; //read the file cfile = (CoronaClassFile) srcPath.getFile(errorFileName + ".java"); // NOI18N char[] data; if (cfile.pis != null) { data = cfile.pis.getString(0).toCharArray(); } else { try { InputStream input = cfile.getInputStream(); try { data = readDataFromIs(input); } finally { input.close(); } } catch (IOException e) { if (Boolean.getBoolean("netbeans.debug.exceptions")) { // NOI18N e.printStackTrace(); } errors = null; return; } } int ilength = data.length; //report the errors for (ErrorMessage msg = errors; msg != null; msg = msg.next) { ErrorMessage tmpmsg; while ((tmpmsg = msg.next) != null && msg.where == tmpmsg.where && msg.message.equals(tmpmsg.message)) { msg = msg.next; if (nwarnings > 1) nwarnings--; else nerrors--; } long ln = msg.where >>> OFFSET_BITS; int off = (int) ((long) msg.where & OFFSET_BITS_MASK); int i; int j; if (off > ilength) { off = ilength; } for (i = off - 1; i > 0 && data[i - 1] != '\n' && data[i - 1] != '\r'; i--) /* null body */ ; for (j = off; j < ilength && data[j] != '\n' && data[j] != '\r'; j++) /* null body */ ; if (i < 0) i = 0; // if off is 0, the i would stay on -1. FIxed bug #3756 - java.lang.StringIndexOutOfBoundsException during compilation String ref = new String(data, i, j - i); errConsumer.pushError(cfile.getFile(), (int) ln, off - 1 - i, msg.message, ref); // else - instanceof ClasFile - err can be only in java - java are "only" in // NOI18N // CoronaClassPath - always - CoronaClassFile } errors = null; } private char[] readDataFromIs(InputStream in) throws java.io.IOException { char[] data = new char[1024]; int off = 0; InputStreamReader ir = new InputStreamReader(in); int ilength; for (;;) { ilength = ir.read(data, off, data.length - off); if (ilength < 0) { char[] ret = new char[off]; System.arraycopy(data, 0, ret, 0, off); data = ret; break; } off += ilength; if (off >= data.length) { // overflow char[] aux = new char[2 * data.length]; System.arraycopy(data, 0, aux, 0, data.length); data = aux; } } return data; } // std hck public void output(String s) { if (errConsumer != null) { errConsumer.pushError(null, -1, -1, s, null); } } /** method for compile method of Compiler */ public Object getDeprElement() { return deprecationFiles.elementAt(0); } public void x_parseFile(ClassFile classfile) throws FileNotFoundException { long l = System.currentTimeMillis(); dtEnter("parseFile: PARSING SOURCE " + classfile); // NOI18N Environment environment = new Environment(this, classfile); JavaParser javaParser = null; try { environment.setCharacterEncoding(getCharacterEncoding()); if (classfile instanceof CoronaClassFile) { CoronaClassFile sourceFile = (CoronaClassFile) classfile; FileObject fo = sourceFile.getFile(); javaParser = createParser(environment, fo); sourceFile.pis = javaParser.input; } else { // classfile found in sys classpath throw new IllegalArgumentException(); } } catch(IOException ex) { dtEvent("parseFile: IO EXCEPTION " + classfile); // NOI18N throw new FileNotFoundException(); } try { javaParser.parseFile(); } catch(Exception exception) { throw new CompilerError(exception); } if(verbose()) { l = System.currentTimeMillis() - l; output(Main.getText("benv.parsed_in", classfile.getPath(), Long.toString(l))); // NOI18N } if(javaParser.getClassesProtected().size() == 0) { javaParser.getImportsProtected().resolve(environment); } else { Enumeration enumeration = javaParser.getClassesProtected().elements(); ClassDefinition classdefinition = (ClassDefinition)enumeration.nextElement(); if(classdefinition.isInnerClass()) throw new CompilerError("BatchEnvironment, first is inner"); // NOI18N ClassDefinition classdefinition1 = classdefinition; while(enumeration.hasMoreElements()) { ClassDefinition classdefinition2 = (ClassDefinition)enumeration.nextElement(); if(!classdefinition2.isInnerClass()) { classdefinition1.addDependency(classdefinition2.getClassDeclaration()); classdefinition2.addDependency(classdefinition1.getClassDeclaration()); classdefinition1 = classdefinition2; } } if(classdefinition1 != classdefinition) { classdefinition1.addDependency(classdefinition.getClassDeclaration()); classdefinition.addDependency(classdefinition1.getClassDeclaration()); } } dtExit("parseFile: SOURCE PARSED " + classfile); // NOI18N } public JavaParser createParser(Environment env, FileObject fo) throws IOException { try { JavaDataObject jdo = (JavaDataObject) DataObject.find(fo); SourceElementImpl source = jdo.getSourceElementImpl(); if ((source.getStatus() == SourceElement.STATUS_NOT) || source.isDirty()) { return new JavaParser(env, fo, true); } } catch (DataObjectNotFoundException e) { } catch (ClassCastException e) { } return new JavaParser(env, fo, false); } int getClassesSize() { int counter = 0; for (Enumeration en = getClasses() ; en.hasMoreElements() ; en.nextElement()) counter++; return counter; } /** Holds messages with errors in CoronaEnvironment * * @author Ales Novak */ static class ErrorMessage { long where; String message; ErrorMessage next; ErrorMessage(long i, String string) { where = i; message = string; } } } /* * Log * 18 Gandalf-post-FCS1.16.2.0 2/24/00 Ian Formanek Post FCS changes * 17 src-jtulach1.16 1/13/00 Petr Hamernik i18n -(2nd round) - * script bug fixed. * 16 src-jtulach1.15 1/12/00 Petr Hamernik i18n: perl script used ( * //NOI18N comments added ) * 15 src-jtulach1.14 11/25/99 Ales Novak fix for 3801, 2929 * 14 src-jtulach1.13 11/25/99 Ales Novak NullPointerException * 13 src-jtulach1.12 11/5/99 Ales Novak #2206 * 12 src-jtulach1.11 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 11 src-jtulach1.10 9/14/99 Ian Formanek Fixed bug 3756 - * java.lang.StringIndexOutOfBoundsException during compilation * 10 src-jtulach1.9 8/27/99 Petr Hamernik Error message became * inner class * 9 src-jtulach1.8 8/17/99 Ales Novak #2206 * 8 src-jtulach1.7 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 7 src-jtulach1.6 5/28/99 Ales Novak environment creation * changed * 6 src-jtulach1.5 4/23/99 Petr Hrebejk Classes temporay made * public * 5 src-jtulach1.4 4/16/99 Petr Hamernik synchronization under * Nodes.MUTEX * 4 src-jtulach1.3 4/8/99 Ian Formanek Removed debug prints * 3 src-jtulach1.2 3/29/99 Petr Hamernik * 2 src-jtulach1.1 3/29/99 Petr Hamernik * 1 src-jtulach1.0 3/28/99 Ales Novak * $ * Beta Change History: * 0 Tuborg 0.20 --/--/98 Jaroslav Tulach allows change of output stream and error consumer */